#######################
#                     #
#  PL0-Idiom Scanner  #
#                     #
#######################


### define lexer class objects

### Tag defines constants for tokens
class Tag(object):
	BEGIN = 256        # begin statement
	CALL = 257         # call procedure
	CONST = 258        # define constant
	DO = 259           # do statement during while condition
	EQ = 260           # equal
	END = 261          # end statement
	GE = 262           # greater equal
	ID = 263           # identifier 
	IF = 264           # if condition
	LE = 265           # less equal
	NE = 266           # not equal
	NUM = 267          # number
	ODD = 268          # odd
	PRINT = 269        # output
	PROCEDURE = 270    # define procedure
	READ = 271         # input
	THEN = 272         # if condition then statement
	VAR = 273          # define variable
	WHILE = 274        # while condition
	PASS = 275         # do nothing
	

### Token defines token for lexer
class Token(object):
	def __init__(self, t):
		self.tag = t
	
	def toString(self):
		return "" + self.tag
	
	
### Num extends Token for defining numbers
class Num(Token):
	def __init__(self, v):
		Token.__init__(self, Tag.NUM)
		self.value = v
		
	def toString(self):
		return "" + str(self.value)
	
	
### Word extends Token for defining reserved words, identifier and connected tokens
class Word(Token):
	def __init__(self, s, tag):
		Token.__init__(self, tag)
		self.lexeme = s
		
	def toString(self):
		return "" + self.lexeme
	
	
### Lexer inerhits symbol table for key words
class Lexer(object):	
	def reserve(self, w):
		self.words[w.lexeme] = w
		
	def __init__(self):
		self.words = {}
		self.peek = ' '
		self.__line = 0
		self.__position = -1
		self.reserve(Word("IF", Tag.IF))
		self.reserve(Word("WHILE", Tag.WHILE))
		self.reserve(Word("DO", Tag.DO))
		self.reserve(Word("THEN", Tag.THEN))
		self.reserve(Word("CALL", Tag.CALL))
		self.reserve(Word("PRINT", Tag.PRINT))
		self.reserve(Word("READ", Tag.READ))
		self.reserve(Word("PROCEDURE", Tag.PROCEDURE))
		self.reserve(Word("ODD", Tag.ODD))
		self.reserve(Word("VAR", Tag.VAR))
		self.reserve(Word("END", Tag.END))
		self.reserve(Word("BEGIN", Tag.BEGIN))
		self.reserve(Word("CONST", Tag.CONST))
		self.reserve(Word("PASS", Tag.PASS))
		self.reserve(Word("==", Tag.EQ))
		self.reserve(Word("!=", Tag.NE))
		self.reserve(Word("<=", Tag.LE))
		self.reserve(Word(">=", Tag.GE))
		
	def getline(self):
		line = self.__line
		return line

	def setCode(self, source_code=[]):
		self.code = source_code
		
	def readnch(self):
		self.__position = self.__position + 1
		while (self.__position > len(self.code[self.__line]) - 1 or len(self.code[self.__line]) == 0):
			self.__line = self.__line + 1
			self.__position = 0
		self.peek = self.code[self.__line][self.__position]				

	def readch(self, c):
		self.readnch()
		if (self.peek != c): return False
		self.peek = ' '
		return True

			
	def scan(self):
		while (self.peek == ' ' or self.peek == '\n' or self.peek == '\t'): 
			self.readnch()
			
		if (self.peek == '='):
			if (self.readch('=')): return self.words['==']
			else: return Token('=')
		if (self.peek == '!'):
			if (self.readch('=')): return self.words['!=']
			else: pass
		if (self.peek == '<'):
			if (self.readch('=')): return self.words['<=']
			else: return Token('<')
		if (self.peek == '>'):
			if (self.readch('=')): return self.words['>=']
			else: return Token('>')
			
		if (self.peek.isdigit()):
			v = 0
			while (self.peek.isdigit()):
				v = 10 * v + int(self.peek)
				self.readnch()
			return Num(v)
		
		if (self.peek.isalpha()):
			b = ''
			while (self.peek.isalnum()):
				b = b + self.peek
				self.readnch()
			
			if (self.words.has_key(b)):
				w = self.words[b]
			else:
				w = None
			
			if (w != None): return w 
			w = Word(b, Tag.ID)
			self.words[b] = w 
			return w
		
		tok = Token(self.peek)
		if (self.peek == '.'): self.peek = ''
		else: self.peek = ' '
		return tok

